﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using blackhouse.BlackApart.Data;
using blackhouse.BlackApart.Business.Calendar;
using blackhouse.BlackApart.Business.Apartments;
using blackhouse.BlackApart.Business.Prices;

namespace blackhouse.BlackApart.Business.Reservations
{
    internal class DaApartmentReservation : IReservation
    {

        #region Fields

        private ICalendar calendar;
        private IReservationDataAccess dataAccess;
        private IApartment apartment;
        private IApartmentPrice price;
        private int apartmentId;

        #endregion

        #region Properties

        public int Id { get; private set; }
        public DateTime StartDate { get; private set; }
        public DateTime EndDate { get; private set; }
        public int NumberOfPeople { get; private set; }
        public IApartment Apartment
        {
            get
            {
                if (apartment == null && apartmentId > 0)
                    this.apartment = Factory.Instance().GetApartment(apartmentId);
                return this.apartment;
            }
            set
            {
                this.apartment = value;
                this.apartmentId = value.Id;
            }
        }

        public IApartmentPrice Price
        {
            get
            {
                if (price == null && apartmentId > 0)
                {
                    this.price = Factory.Instance().GetApartmentPrice(this.apartmentId);
                    this.price.ReservationFromDay = this.StartDate;
                    this.price.ReservationToDay = this.EndDate;
                    this.price.ReservationNumberOfPeoples = this.NumberOfPeople;
                }
                return this.price;
            }
            set
            {
                this.price = value;
            }
        }

        #endregion

        #region Constructors

        public DaApartmentReservation(IReservationDataAccess data) : this(null, data) { }

        public DaApartmentReservation(ICalendar dueCalendar, IReservationDataAccess data)
        {
            this.calendar = dueCalendar;
            this.dataAccess = data;
        }

        public DaApartmentReservation(ReservationData data, ICalendar calendar, IReservationDataAccess iCalendarDataAccess)
        {
            this.calendar = calendar;
            this.dataAccess = iCalendarDataAccess;
            this.Id = data.Id;
            this.StartDate = data.StartDate;
            this.EndDate = data.EndDate;
            this.NumberOfPeople = data.NumberOfPeople;
            this.apartmentId = data.ApartmentId;
        }

        #endregion

        #region Methods

        public void SetStartDate(DateTime date)
        {
            this.SetStartDate(date, false);
        }

        public void SetStartDate(DateTime date, bool useOrginalTime)
        {
            if (!useOrginalTime)
                date = date.Date.AddHours(14);
            this.StartDate = date;
        }

        public void SetEndDate(DateTime date)
        {
            this.SetEndDate(date, false);
        }

        public void SetEndDate(DateTime date, bool useOrginalTime)
        {
            if (!useOrginalTime)
                date = date.Date.AddHours(12);
            this.EndDate = date;
        }

        public void SetForNumberOfPeople(int numberOfPeople)
        {
            this.NumberOfPeople = numberOfPeople;
        }

        public bool Save()
        {
            if (this.EndDate < DateTime.Now) return false; // nie można dodać rezerwacji która już się skończyła
            if (this.EndDate < this.StartDate) return false;
            if (this.NumberOfPeople <= 0) return false;
            if (this.calendar is DaApartmentCalendar
                    && calendar.Apartment.NumberOfPeople < this.NumberOfPeople) return false; // Rezerwacja jest na więcej osób niż pomieści apartament
            try
            {
                IApartmentPrice price = this.Price;
                this.Id = this.dataAccess.SaveReservation(this.Id,
                    this.calendar.Apartment.Id,
                    (price != null) ? price.GetPrice() : 0,
                    (price != null) ? price.GetPriceWithoutRabat() : 0,
                    (price != null) ? price.GetRabat() : 0,
                    this.NumberOfPeople,
                    this.StartDate,
                    this.EndDate);
            }
            catch (ExceptionData ed)
            {
                if (ed.Code == 1)
                    throw new ExceptionNotFreeApartment(ed);
            }
            return (this.Id > 0);
        }

        public IReservation[] GetReservations(ICalendar calendar, DateTime startDate, DateTime endDate)
        {
            return this.dataAccess.GetReservations(calendar.Apartment.Id, startDate, endDate).Select(rd => this.ConvertToInstance(rd, calendar)).ToArray();
        }

        private IReservation ConvertToInstance(ReservationData data, ICalendar calendar)
        {
            return new DaApartmentReservation(data, calendar, this.dataAccess);
        }

        public bool Remove()
        {
            return this.dataAccess.RemoveReservation(this.Id);
        }

        #endregion

    }
}
